package com.example.reflection;

import com.example.reflection.entity.User;
import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author readpage
 * @create 2022-10-21 19:25
 * 调用运行时类中指定的结构: 属性、方法、构造器
 */
public class Reflection2Test {
    /**
     *
     */
    @Test
    public void testField() throws NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class<User> clazz = User.class;
        // 创建运行时类的对象
        User user = clazz.getConstructor().newInstance();
        // 获取指定的属性： 要求运行时类中属性声明为public
        //通常不采用此方法
        Field id = clazz.getField("id");
        //设置当前属性的值
        //set(): 参数1: 指明设置哪个对象的属性  参数2： 将此属性值设置为多少
        id.set(user, 1111);

        /**
         * 获取当前属性的值
         * get(): 参数: 获取哪个对象的当前属性值
         */
        int uid = (int) id.get(user);
        System.out.println(uid);
    }


    @Test
    public void testField2() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        Class<User> clazz = User.class;

        //2. 创建运行时类的对象
        User user = clazz.getConstructor().newInstance();

        //getDeclaredField(String fieldName): 获取运行时类中指定变量名的属性
        Field name = clazz.getDeclaredField("name");
        // 2.保证当前属性是可访问的
        name.setAccessible(true);
        name.set(user, "Tom");

        System.out.println(name.get(user));
    }

    /**
     * 如何操作运行时中的指定的方法
     */
    @Test
    public void testMethod() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class<User> clazz = User.class;

        //创建运行时类的对象
        User user = clazz.getConstructor().newInstance();

        /**
         * 1.获取指定某个方法
         * getDeclaredMethod(): 参数1: 指明获取的方法的名称 参数2: 形参列表
         */
        Method show = clazz.getDeclaredMethod("show", String.class);
        // 2.保证当前方法是可访问的
        show.setAccessible(true);
        /**
         * invoke(): 参数1： 方法的调用者 参数2: 给方法形参赋值的实参
         * invoke()的返回值即为类中调用的方法的返回值
         */
        Object returnValue = show.invoke(user, "july");
        System.out.println(returnValue);

        System.out.println("********如何调用静态方法*************");

        // private static void showDesc()
        Method showDesc = clazz.getDeclaredMethod("showDesc");
        showDesc.setAccessible(true);
        //如果调用时运行时类中的方法没有返回值，则此invoke为null
//        Object returnVal = showDesc.invoke(null);
        Object returnVal = showDesc.invoke(User.class);
        System.out.println(returnVal);  //null
    }

    //如何调用运行时类中的指定的构造器
    @Test
    public void testConstructor() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class<User> clazz = User.class;

        //private Use(String name)
        /**
         * 1.获取指定的构造器
         * getDeclaredConstructor(): 参数: 指明构造器的参数列表
         */
        Constructor<User> constructor = clazz.getDeclaredConstructor(String.class);

        //2.保证此构造器是可访问的
        constructor.setAccessible(true);

        //3.调用此构造器创建运行时类的对象
        User user = constructor.newInstance("Tom");
        System.out.println(user);
    }
}
